package com.hdax.dm.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdax.dm.Vo.EsQuerygoodsinfosVo;
import com.hdax.dm.dto.*;
import com.hdax.dm.entity.base.Image;
import com.hdax.dm.entity.item.DmCinema;
import com.hdax.dm.entity.item.DmItem;
import com.hdax.dm.entity.item.DmItemType;
import com.hdax.dm.feign.ImageFeign;
import com.hdax.dm.mappers.ItemTypeMapper;
import com.hdax.dm.mapstrucs.ItemCinemaDtoMapper;
import com.hdax.dm.mapstrucs.SortgoodsDtoMapper;
import com.hdax.dm.service.CinemaService;
import com.hdax.dm.service.EsService;
import com.hdax.dm.service.ItemTypeService;
import com.hdax.dm.utils.response.CommonResponse;
import com.hdax.dm.utils.response.ResponseUtil;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.document.DocumentField;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@Service
public class EsSImpl extends ServiceImpl<ItemTypeMapper,DmItemType > implements EsService {


    private static final String ZERO_TIME_STR=" 00:00:00";

    private static final String ELEVEN_TIME_STR=" 23:59:59";

    @Autowired
    private CinemaService cinemaService;


    @Autowired
    private ImageFeign imageFeign;

    @Autowired
    private SortgoodsDtoMapper sortgoodsDtoMapper;

    //在最新版这个已经过时了，8的版本就不一样了
    @Autowired
    private RestHighLevelClient client;


    public String ggImageFeign(Long targetId,Long type,Long category){
        //通过openfeign远程调用了base，查询图片信息
        Image image=imageFeign.image(targetId, type, category);
        String imageUrl=image==null?"": image.getImgUrl();
        return imageUrl;
    }


    @Override
    public CommonResponse<List<SortgoodsDto>> sortgoods(Integer parent) {
        QueryWrapper<DmItemType> wrapper=new QueryWrapper<>();
        wrapper.eq("parent",parent);
        List<SortgoodsDto> indexNavDtos=sortgoodsDtoMapper.toTargets(list(wrapper));
        return ResponseUtil.returnSuccess(indexNavDtos);
    }

    @Override
    public CommonResponse<EsItemDto> querygoodsinfos(EsQuerygoodsinfosVo vo) throws IOException {

        //最终响应的Dto对象
        EsItemDto esItemDto=new EsItemDto();

        //ES搜索、检索请求对象
        SearchRequest request=new SearchRequest("items");
        //构建查询条件，搜索条件构造器：负者进行多条件拼装
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        //语法高亮建造器（关键词颜色不同）
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        //多条件查询，
        BoolQueryBuilder boolQueryBuilder= QueryBuilders.boolQuery(); //QueryBuilders：建立所有查询构造器  比如：精确查找、匹配度查找
        //条件1：关键词匹配度查询
        if (StringUtils.hasLength(vo.getKeyword())){       //hasLength：字符不为null,并且字符序列的长度大于0,则返回 true
            //语法高亮
            HighlightBuilder.Field fieldItemname=new HighlightBuilder.Field("itemname");
            fieldItemname.highlighterType("unified");   //unified：ES自带的语法高亮器
            HighlightBuilder.Field fieldAbstractmessage=new HighlightBuilder.Field("abstractmessage");
            fieldAbstractmessage.highlighterType("unified");
            highlightBuilder.fields().add(fieldItemname);
            highlightBuilder.fields().add(fieldAbstractmessage);

            boolQueryBuilder.must(QueryBuilders.matchQuery("itemname",vo.getKeyword()));

            //如何abstractmessage中也出现keyword，得分会更高
            boolQueryBuilder.should(QueryBuilders.matchQuery("abstractmessage",vo.getKeyword()));

        }
        //所在地区
        if(vo.getAreaId()!=0){
            //精确查找：不打分，不排名
            boolQueryBuilder.must(QueryBuilders.termQuery("areaid",vo.getAreaId()));
        }
        //一二级分类
        if(vo.getItemTypeId1()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("itemtype1id",vo.getItemTypeId1()));
        }
        if(vo.getItemTypeId2()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("itemtype2id",vo.getItemTypeId2()));
        }
        //时间范围查询：rangeQuery
        if (StringUtils.hasLength(vo.getStartTime()) && StringUtils.hasLength(vo.getEndTime())){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("starttime");
            //设置时间的起止范围
            rangeQueryBuilder.gte(vo.getStartTime().concat(ZERO_TIME_STR));
            rangeQueryBuilder.lte(vo.getEndTime().concat(ELEVEN_TIME_STR));

            boolQueryBuilder.must(rangeQueryBuilder);
        }
        //排序查询
        String sortField="isrecommend";
        switch (vo.getSort()){
            case "recommend": sortField="isrecommend"; break;
            case "recentShow": sortField="starttime"; break;
            case "recentSell": sortField="createdtime"; break;
        }
        sourceBuilder.sort(sortField, SortOrder.DESC);

        //设置高亮的样式
        //设定语法高亮的字段不会自动添加到es的field中
        highlightBuilder.requireFieldMatch(true);   //设置属性的高亮匹配
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

        //多条件被封装进来了
        sourceBuilder.query(boolQueryBuilder);

        //分页处理
        sourceBuilder.from((vo.getCurrentPage()-1)*vo.getPageSize());
        sourceBuilder.size(vo.getPageSize());

        //拼装完条件，转换成JSON数据向ES发送
        request.source(sourceBuilder);

        //ES响应的对象           程序向es访问是借助RestHighLevelClient有他来发送
        SearchResponse response=client.search(request, RequestOptions.DEFAULT);//RequestOptions：请求选项，默认

        //获取本次查询总条数
        SearchHits hit=response.getHits();
        int totalCount=(int) hit.getTotalHits().value;     //总条数

        esItemDto.setPageCount(totalCount % vo.getPageSize()==0?totalCount / vo.getPageSize():totalCount / vo.getPageSize()+1);    //总页数
        esItemDto.setCurrentPage(vo.getCurrentPage()); //当前页码
        esItemDto.setPageSize(vo.getPageSize());     //每页数
        esItemDto.setTotal(totalCount);

        //第一次hits拿到的是总数
        //第二次hits才能拿到数据集合
        SearchHit[] hits = response.getHits().getHits();

        for (int i = 0; i < hits.length; i++) {
            //每一行搜索到的商品数据                      //JSON会从SourceAsString来解析数据信息，按照指定属性和实体类dto匹配
            EsItemCinemaDto esItemCinemaDto= JSON.parseObject(hits[i].getSourceAsString(),EsItemCinemaDto.class);
            esItemCinemaDto.setImgUrl(ggImageFeign(esItemCinemaDto.getId(),2L,1L));
            if (StringUtils.hasLength(vo.getKeyword())){
                esItemCinemaDto.setItemName(StringUtils.arrayToDelimitedString(hits[i].getHighlightFields().get("itemname").getFragments(),""));
                if (hits[i].getHighlightFields().get("abstractmessage")!=null){
                    esItemCinemaDto.setAbstractMessage(StringUtils.arrayToDelimitedString(hits[i].getHighlightFields().get("abstractmessage").getFragments(),""));
                }
            }
            esItemDto.getRows().add(esItemCinemaDto);
            String cinemaid = JSONObject.parseObject(hits[i].getSourceAsString()).getString("cinemaid");
            DmCinema cinema= cinemaService.cinemaOne(Long.parseLong(cinemaid));
            esItemCinemaDto.setAddress(cinema.getAddress());
            esItemCinemaDto.setAreaId(cinema.getAreaId());
            esItemCinemaDto.setAreaName(cinema.getAreaName());
        }
        return ResponseUtil.returnSuccess(esItemDto);
    }

}
